import datetime
import socket
import threading
import time
import traceback


def log(*text):
    text = str(datetime.datetime.now())[:19] + "--" + ", ".join([str(i) for i in text])
    print(text)
    return text + "\n\n"


def thread_it(func, *args):
    t = threading.Thread(target=func, args=args)
    t.setDaemon(True)
    t.start()


class my_socket:
    def __init__(self) -> None:
        self.send_queue = []

    def send(self, send_address, send_port, message):
        now = time.time()
        self.send_queue.append((send_address, send_port, message, now))

    def do_send(self, send_address, send_port, message):
        self.send_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.send_socket.connect((send_address, send_port))
        self.send_socket.send(str(message).encode())
        self.send_socket.close()

    def delete(self, del_index):
        del self.send_queue[del_index]

    def update_thread(self, delay=5):
        while True:
            try:
                now = time.time()
                delete_list = []
                for i in self.send_queue:
                    if now - i[3] > delay:
                        self.do_send(i[0], i[1], i[2])
                        delete_list.append(i)
                for i in delete_list:
                    self.send_queue.remove(i)
            except:
                print(traceback.format_exc())
                break

    def run(self):
        thread_it(self.update_thread)


delay_socket = my_socket()
delay_socket.run()


class send_queue:
    def __init__(self, seq_count, send_window_size):
        self.serial_number_to_be_sent = []
        self.have_send = set()  # 已经发送的序列号
        self.have_ack = set()
        self.send_time = dict()
        self.send_window = [0, send_window_size]
        for i in range(1, seq_count + 1):
            self.serial_number_to_be_sent.append(i)

    def get(self):
        # 返回下一个要发送的序列号
        if len(self.serial_number_to_be_sent) == 0:
            return None
        for i in range(self.send_window[0], self.send_window[1]):
            if self.serial_number_to_be_sent[i] not in self.have_send:
                return self.serial_number_to_be_sent[i]
        return None

    def do_send(self, seq_num, send_time):
        self.have_send.add(seq_num)
        self.send_time[seq_num] = send_time

    def update(self, now, timeout=15):
        # 删除超时的已发送
        delete_list = []
        for i in self.have_send:
            if now - self.send_time[i] > timeout:
                delete_list.append(i)
        for i in delete_list:
            self.have_send.remove(i)

    def ack(self, ack_num):
        self.have_ack.add(ack_num)
        # 更新发送窗口
        while self.serial_number_to_be_sent[self.send_window[0]] in self.have_ack:
            self.send_window[0] += 1
            self.send_window[1] = min(
                self.send_window[1] + 1, len(self.serial_number_to_be_sent)
            )
            if self.send_window[0] == len(self.serial_number_to_be_sent):
                break


class sender:
    def __init__(self, name, address, send_port, receive_port):
        self.name = name
        self.address = address
        self.send_port = send_port
        self.receive_port = receive_port
        self.send_socket = None
        self.receive_socket = None

        self.send_queue = send_queue(16, 5)

    def send(self, message):
        global delay_socket
        log("sender send:%s" % message)
        delay_socket.send(self.address, self.send_port, message)

    def receive(self):
        self.receive_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.receive_socket.bind((self.address, self.receive_port))
        self.receive_socket.listen(1)
        client_socket, client_address = self.receive_socket.accept()
        message = client_socket.recv(1024).decode()
        log("sender receive:%s" % message)
        self.receive_socket.close()
        return message

    def run_send_thread(self):
        while True:
            try:
                now = time.time()
                self.send_queue.update(now)
                # 取出下一个要发送的序列号
                seq_num = self.send_queue.get()
                if seq_num is not None:
                    # 发送
                    self.send(seq_num)
                    self.send_queue.do_send(seq_num, now)
                time.sleep(1)
            except:
                log(traceback.format_exc())
                break

    def run_receive_thread(self):
        while True:
            try:
                message = self.receive()
                self.send_queue.ack(int(message))
            except:
                log(traceback.format_exc())
                # break

    def run(self):
        thread_it(self.run_receive_thread)
        time.sleep(0.1)
        thread_it(self.run_send_thread)


class receiver:
    def __init__(self, name, address, send_port, receive_port):
        self.name = name
        self.address = address
        self.send_port = send_port
        self.receive_port = receive_port
        self.send_socket = None
        self.receive_socket = None

        self.last_received_ack = None

    def send(self, message):
        global delay_socket
        log("receiver send:%s" % message)
        delay_socket.send(self.address, self.send_port, message)

    def receive(self):
        self.receive_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.receive_socket.bind((self.address, self.receive_port))
        self.receive_socket.listen(1)
        client_socket, client_address = self.receive_socket.accept()
        message = client_socket.recv(1024).decode()
        log("receiver receive:%s" % message)
        self.receive_socket.close()
        return message

    def run_receive_thread(self):
        while True:
            try:
                message = self.receive()
                self.last_received_ack = int(message)
                self.send(int(message))
            except:
                log(traceback.format_exc())
                # break

    def run(self):
        thread_it(self.run_receive_thread)


def test_sender_and_receiver():
    sender_ = sender("sender", "127.0.0.1", 10000, 10001)
    receiver_ = receiver("receiver", "127.0.0.1", 10001, 10000)
    sender_.run()
    receiver_.run()
    while True:
        try:
            time.sleep(0.5)
        except KeyboardInterrupt:
            log("KeyboardInterrupt")
            break


if __name__ == '__main__':
    test_sender_and_receiver()
